/*
 * To change this template, choose Tools | Templates
 * and open the template in the editor.
 */
package jeuxEnConsole;

import java.util.HashSet;
import java.util.regex.Matcher;
import java.util.regex.Pattern;

/**
 *
 * @author julien
 */
public class PlateauCaracteres implements Cloneable {

    static final int largeurPlateau = 5;
    static final int nbPiecesReserve = 5;
    protected char[][] tabCaracteres;

    public PlateauCaracteres() {
        tabCaracteres = new char[largeurPlateau][largeurPlateau];

        for (int i = 0; i < largeurPlateau; i++) {
            for (int j = 0; j < largeurPlateau; j++) {
                tabCaracteres[i][j] = 'X';
            }
        }

        tabCaracteres[2][1] = 'M';
        tabCaracteres[2][2] = 'M';
        tabCaracteres[2][3] = 'M';

    }

    public PlateauCaracteres(char[][] tabCaracteres) {
        this.tabCaracteres = tabCaracteres;
    }

    public char getPiece(int y, int x) {
        return tabCaracteres[y][x];
    }

    public char[][] getTabCaracteres() {
        return tabCaracteres;
    }

    public void setTabCaracteres(char[][] tabCaracteres) {
        for (int i = 0; i < largeurPlateau; i++) {
            for (int j = 0; j < largeurPlateau; j++) {
                this.tabCaracteres[i][j] = tabCaracteres[i][j];
            }
        }
    }

    public boolean a3Montagnes() {
        int nbMontagne = 0;

        for (int i = 0; i < largeurPlateau; i++) {
            for (int j = 0; j < largeurPlateau; j++) {
                if (tabCaracteres[i][j] == 'M') {
                    nbMontagne++;
                }
            }
        }

        return nbMontagne >= 3;
    }

    /**
     * Compte le nombre de piece sur le plateau du même type que la piece passé
     * en paramètre (rhino ou éléphant)
     *
     * @param piece une pièce
     * @return le nombre de pièce du même type présent sur le plateau
     */
    public int getNbSurPlateau(char piece) {
        boolean pieceMajuscule = Character.isUpperCase(piece);
        int nbDePiece = 0;

        if (pieceMajuscule) {
            for (int i = 0; i < largeurPlateau; i++) {
                for (int j = 0; j < largeurPlateau; j++) {
                    if (tabCaracteres[i][j] == 'N'
                            || tabCaracteres[i][j] == 'S'
                            || tabCaracteres[i][j] == 'E'
                            || tabCaracteres[i][j] == 'O') {
                        nbDePiece++;
                    }
                }
            }
        } else {
            for (int i = 0; i < largeurPlateau; i++) {
                for (int j = 0; j < largeurPlateau; j++) {
                    if (tabCaracteres[i][j] == 'n'
                            || tabCaracteres[i][j] == 's'
                            || tabCaracteres[i][j] == 'e'
                            || tabCaracteres[i][j] == 'o') {
                        nbDePiece++;
                    }
                }
            }
        }

        return nbDePiece;
    }

    /**
     * Renvoie true si piece peut pousser la chaine de piece obstacles
     *
     * @param piece la piece qui pousse
     * @param obstacles la liste d'obstacles sous forme de caractères
     * @return true si la piece peut pousser les obstacles
     */
    public boolean peutPousser(char piece, String obstacles) {
        int force = 1;
        char pieceOpose = 'X';
        // un booléen pour sauté le poids de la première montagne
        boolean sauterPoidsPremiereMontagne = false;

        piece = Character.toLowerCase(piece);
        obstacles = obstacles.toLowerCase();

        if (piece == 'n') {
            pieceOpose = 's';
        } else if (piece == 's') {
            pieceOpose = 'n';
        } else if (piece == 'e') {
            pieceOpose = 'o';
        } else if (piece == 'o') {
            pieceOpose = 'e';
        }

        for (int i = 0; i < obstacles.length(); i++) {
            char c = obstacles.charAt(i);
            if (c == 'x') {
                break;
            }
            if (c == pieceOpose) {
                force--;
            } else if (c == piece) {
                if (i < obstacles.length()) {
                    for (int j = i + 1; j < obstacles.length(); j++) {
                        char prochainObstacle = obstacles.charAt(j);
                        if (prochainObstacle == 'm' || prochainObstacle == pieceOpose) {
                            force++;
                            break;
                        }
                    }
                }
            } else if (c == 'm') {
                if (sauterPoidsPremiereMontagne) {
                    force--;
                } else {
                    sauterPoidsPremiereMontagne = true;
                }
            }
        }
        return force > 0;

    }

    /**
     * Calcul les changements dans la chaine aprés l'insertion d'un caractère en
     * première place en suivant les règles du siam.
     *
     * @param piece
     * @param obstacles
     * @return la nouvelle chaine avec le caractère inséré
     */
    private String calculDeplacementChaine(char piece, String obstacles) {
        String nouvelleChaineObstacle = new String();
        int placePremiereCaseVide = 0;

        while (placePremiereCaseVide < obstacles.length()
                && obstacles.charAt(placePremiereCaseVide) != 'X') {
            placePremiereCaseVide++;
        }

        nouvelleChaineObstacle += piece;

        for (int i = 0; i < placePremiereCaseVide; i++) {
            nouvelleChaineObstacle += obstacles.charAt(i);
        }
        if (placePremiereCaseVide < obstacles.length() - 1) {
            nouvelleChaineObstacle += obstacles.substring(placePremiereCaseVide + 1);
        }
        if (nouvelleChaineObstacle.length() > obstacles.length()) {
            nouvelleChaineObstacle = nouvelleChaineObstacle.substring(0, obstacles.length());
        }

        return nouvelleChaineObstacle;
    }

    @Override
    public String toString() {
        String chaine = "===========\n";
        for (int i = 0; i < largeurPlateau; i++) {
            for (int j = 0; j < largeurPlateau; j++) {
                chaine += tabCaracteres[i][j];
            }
            chaine += '\n';
        }
        chaine += "===========\n";
        return chaine;
    }

    public boolean coupValide(String coup) {
        switch (coup.charAt(0)) {
            case 'I':
                return coupInsertionValide(coup);
            case 'D':
                return coupDeplacementValide(coup);
            default:
                return false;
        }
    }

    /**
     * Joue une coup donné sous la forme d'une chaine: insertion: I(0,4):S
     * déplacement: D(0,3)(0,4):N rotation: R(2,2):N poucer: P(0,2)
     *
     * @param coup
     */
    public void jouerCoup(String coup) throws Exception {
        switch (coup.charAt(0)) {
            case 'I':
                if (coupInsertionValide(coup)) {
                    insererPiece(coup);
                } else {
                    throw new Exception("Le coup d'insertion spécifié n'est pas valide");
                }
                break;
            case 'D':
                if (coupDeplacementValide(coup)) {
                    deplacerPiece(coup);
                } else {
                    throw new Exception("Le coup de déplacement spécifié n'est pas valide");
                }
                break;
            default:
                throw new Exception("Coup de type indeterminé.");
        }
    }

    public boolean coupInsertionValide(String coup) {

        Pattern pattern = Pattern.compile("^I\\(("
                + "0,[0-" + (largeurPlateau - 1) + "]"
                + "|" + (largeurPlateau - 1) + ",[0-" + (largeurPlateau - 1) + "]"
                + "|[0-" + (largeurPlateau - 1) + "],0"
                + "|[0-" + (largeurPlateau - 1) + "]," + (largeurPlateau - 1) + ""
                + ")\\):([nseoNSEO])");
        Matcher matcher = pattern.matcher(coup);
        if (matcher.find()) {
            String coord = matcher.group(1);
            String[] tabCoord = coord.split(",");

            int coordY = Integer.valueOf(tabCoord[0]);
            int coordX = Integer.valueOf(tabCoord[1]);
            char piece = matcher.group(2).charAt(0);

            // Si les coordonnées sont hors du plateau
            // ou si le nombre de piece est inférieur à 5
            //TODO supprimer conditionscoordonnees car regex
            if (coordX < 0 || coordX > largeurPlateau - 1
                    || coordY < 0 || coordY > largeurPlateau - 1
                    || getNbSurPlateau(piece) >= nbPiecesReserve) {
                return false;
            } else {
                if (tabCaracteres[coordY][coordX] == 'X') {
                    return true;
                } else {
                    String obstacles = "";
                    // Si on insère sur le coin haut gauche
                    if (coordX == 0 && coordY == 0) {
                        if (piece == 'e' || piece == 'E') {
                            for (int i = coordX; i < largeurPlateau
                                    && tabCaracteres[coordY][i] != 'X'; i++) {
                                obstacles += tabCaracteres[coordY][i];
                            }
                            return peutPousser(piece, obstacles);
                        } else if (piece == 's' || piece == 'S') {
                            for (int i = coordY; i < largeurPlateau
                                    && tabCaracteres[i][coordX] != 'X'; i++) {
                                obstacles += tabCaracteres[i][coordX];
                            }
                            return peutPousser(piece, obstacles);
                        } else {
                            return false;
                        }
                    } // Si on insère sur le coin bas gauche
                    else if (coordX == 0 && coordY == largeurPlateau - 1) {
                        if (piece == 'e' || piece == 'E') {
                            for (int i = coordX; i < largeurPlateau
                                    && tabCaracteres[coordY][i] != 'X'; i++) {
                                obstacles += tabCaracteres[coordY][i];
                            }
                            return peutPousser(piece, obstacles);
                        } else if (piece == 'n' || piece == 'N') {
                            for (int i = coordY;
                                    i >= 0 && tabCaracteres[i][coordX] != 'X'; i--) {
                                obstacles += tabCaracteres[i][coordX];
                            }
                            return peutPousser(piece, obstacles);
                        } else {
                            return false;
                        }
                    }// Si on insère sur le coin haut droit
                    else if (coordX == largeurPlateau - 1 && coordY == 0) {
                        if (piece == 'o' || piece == 'O') {
                            for (int i = coordX; i >= 0
                                    && tabCaracteres[coordY][i] != 'X'; i--) {
                                obstacles += tabCaracteres[coordY][i];
                            }
                            return peutPousser(piece, obstacles);
                        } else if (piece == 's' || piece == 'S') {
                            for (int i = coordY;
                                    i < largeurPlateau
                                    && tabCaracteres[i][coordX] != 'X'; i++) {
                                obstacles += tabCaracteres[i][coordX];
                            }
                            return peutPousser(piece, obstacles);
                        } else {
                            return false;
                        }
                    }// Si on insère sur le coin bas droit
                    else if (coordX == largeurPlateau - 1 && coordY == largeurPlateau - 1) {
                        if (piece == 'o' || piece == 'O') {
                            for (int i = coordX; i >= 0
                                    && tabCaracteres[coordY][i] != 'X'; i--) {
                                obstacles += tabCaracteres[coordY][i];
                            }
                            return peutPousser(piece, obstacles);
                        } else if (piece == 'n' || piece == 'N') {
                            for (int i = coordY;
                                    i >= 0
                                    && tabCaracteres[i][coordX] != 'X'; i--) {
                                obstacles += tabCaracteres[i][coordX];
                            }
                            return peutPousser(piece, obstacles);
                        } else {
                            return false;
                        }
                    }// Si on insère sur le coté gauche
                    else if (coordX == 0
                            && coordY > 0
                            && coordY < largeurPlateau - 1) {
                        if (piece == 'e' || piece == 'E') {
                            for (int i = coordX; i < largeurPlateau
                                    && tabCaracteres[coordY][i] != 'X'; i++) {
                                obstacles += tabCaracteres[coordY][i];
                            }
                            return peutPousser(piece, obstacles);
                        } else {
                            return false;
                        }
                    }// Si on insère sur le coté droit
                    else if (coordX == largeurPlateau - 1
                            && coordY > 0
                            && coordY < largeurPlateau - 1) {
                        if (piece == 'o' || piece == 'O') {
                            for (int i = coordX; i >= 0
                                    && tabCaracteres[coordY][i] != 'X'; i--) {
                                obstacles += tabCaracteres[coordY][i];
                            }
                            return peutPousser(piece, obstacles);
                        } else {
                            return false;
                        }
                    }// Si on insère sur le coté haut
                    else if (coordY == 0
                            && coordX > 0
                            && coordX < largeurPlateau - 1) {
                        if (piece == 's' || piece == 'S') {
                            for (int i = coordY; i < largeurPlateau
                                    && tabCaracteres[i][coordX] != 'X'; i++) {
                                obstacles += tabCaracteres[i][coordX];
                            }
                            return peutPousser(piece, obstacles);
                        } else {
                            return false;
                        }
                    }// Si on insère sur le coté bas
                    else if (coordY == largeurPlateau - 1
                            && coordX > 0
                            && coordX < largeurPlateau - 1) {
                        if (piece == 'n' || piece == 'N') {
                            for (int i = coordY; i >= 0
                                    && tabCaracteres[i][coordX] != 'X'; i--) {
                                obstacles += tabCaracteres[i][coordX];
                            }
                            return peutPousser(piece, obstacles);
                        } else {
                            return false;
                        }
                    } else {
                        return false;
                    }
                }
            }
        } else {
            return false;
        }
    }

    public boolean coupDeplacementValide(String coup) {
        Pattern pattern = Pattern.compile("^D\\("
                + "([0-" + (largeurPlateau - 1) + "]),"
                + "([0-" + (largeurPlateau - 1) + "])"
                + "\\)\\("
                + "(-?[0-" + (largeurPlateau - 1) + "]),"
                + "(-?[0-" + (largeurPlateau - 1) + "])"
                + "\\):([nseoNSEO])");
        Matcher matcher = pattern.matcher(coup);
        if (matcher.find()) {
            int coord1Y = Integer.valueOf(matcher.group(1));
            int coord1X = Integer.valueOf(matcher.group(2));
            int coord2Y = Integer.valueOf(matcher.group(3));
            int coord2X = Integer.valueOf(matcher.group(4));
            char piece = matcher.group(5).charAt(0);

            // Si la piece du tableau de caractère correspond au type de
            // pièce spécifié dans le coups
            if (Character.isLowerCase(tabCaracteres[coord1Y][coord1X])
                    && Character.isLowerCase(piece)
                    || Character.isUpperCase(tabCaracteres[coord1Y][coord1X])
                    && tabCaracteres[coord1Y][coord1X] != 'M'
                    && tabCaracteres[coord1Y][coord1X] != 'X'
                    && Character.isUpperCase(piece)) {

                String obstacles = new String();

                // Si on effectue une simple rotation
                if (coord1X == coord2X
                        && coord1Y == coord2Y) {
                    return true;
                }// Si on déplace la piece vers le haut
                else if (coord2X == coord1X && coord2Y == coord1Y - 1) {
                    if (coord2Y < 0) {
                        return true;
                    } else {
                        if (tabCaracteres[coord2Y][coord2X] == 'X') {
                            return true;
                        } else if (tabCaracteres[coord2Y][coord2X] != 'X'
                                && piece != tabCaracteres[coord1Y][coord1X]) {
                            return false;
                        } else {
                            for (int i = coord2Y; i >= 0; i--) {
                                obstacles += tabCaracteres[i][coord1X];
                            }
                            return (tabCaracteres[coord1Y][coord1X] == 'n'
                                    || tabCaracteres[coord1Y][coord1X] == 'N')
                                    && peutPousser(tabCaracteres[coord1Y][coord1X], obstacles);
                        }
                    }
                }// Si on déplace la piece vers le bas
                else if (coord2X == coord1X && coord2Y == coord1Y + 1) {
                    if (coord2Y >= largeurPlateau) {
                        return true;
                    } else {
                        if (tabCaracteres[coord2Y][coord2X] == 'X') {
                            return true;
                        } else if (tabCaracteres[coord2Y][coord2X] != 'X'
                                && piece != tabCaracteres[coord1Y][coord1X]) {
                            return false;
                        } else {
                            for (int i = coord2Y; i < largeurPlateau; i++) {
                                obstacles += tabCaracteres[i][coord1X];
                            }
                            return (tabCaracteres[coord1Y][coord1X] == 's'
                                    || tabCaracteres[coord1Y][coord1X] == 'S')
                                    && peutPousser(tabCaracteres[coord1Y][coord1X], obstacles);
                        }
                    }
                }// Si on déplace la piece vers la gauche
                else if (coord2Y == coord1Y && coord2X == coord1X - 1) {
                    if (coord2X < 0) {
                        return true;
                    } else {
                        if (tabCaracteres[coord2Y][coord2X] == 'X') {
                            return true;
                        } else if (tabCaracteres[coord2Y][coord2X] != 'X'
                                && piece != tabCaracteres[coord1Y][coord1X]) {
                            return false;
                        } else {
                            for (int i = coord2X; i >= 0; i--) {
                                obstacles += tabCaracteres[coord1Y][i];
                            }
                            return (tabCaracteres[coord1Y][coord1X] == 'o'
                                    || tabCaracteres[coord1Y][coord1X] == 'O')
                                    && peutPousser(tabCaracteres[coord1Y][coord1X], obstacles);
                        }
                    }
                }// Si on déplace la piece vers la droite
                else if (coord2Y == coord1Y && coord2X == coord1X + 1) {
                    if (coord2X >= largeurPlateau) {
                        return true;
                    } else {
                        if (tabCaracteres[coord2Y][coord2X] == 'X') {
                            return true;
                        } else if (tabCaracteres[coord2Y][coord2X] != 'X'
                                && piece != tabCaracteres[coord1Y][coord1X]) {
                            return false;
                        } else {
                            for (int i = coord2X; i < largeurPlateau; i++) {
                                obstacles += tabCaracteres[coord1Y][i];
                            }
                            return (tabCaracteres[coord1Y][coord1X] == 'e'
                                    || tabCaracteres[coord1Y][coord1X] == 'E')
                                    && peutPousser(tabCaracteres[coord1Y][coord1X], obstacles);
                        }
                    }
                } else {
                    return false;
                }
            } else {
                return false;
            }
        } else {
            return false;
        }
    }

    public void insererPiece(String coup) throws Exception {
        if (coupInsertionValide(coup)) {
            Pattern pattern = Pattern.compile("^I\\(("
                    + "0,[0-" + (largeurPlateau - 1) + "]"
                    + "|" + (largeurPlateau - 1) + ",[0-" + (largeurPlateau - 1) + "]"
                    + "|[0-" + (largeurPlateau - 1) + "],0"
                    + "|[0-" + (largeurPlateau - 1) + "]," + (largeurPlateau - 1) + ""
                    + ")\\):([nseoNSEO])");

            Matcher matcher = pattern.matcher(coup);
            if (matcher.find()) {
                String coord = matcher.group(1);
                String[] tabCoord = coord.split(",");

                int coordY = Integer.valueOf(tabCoord[0]);
                int coordX = Integer.valueOf(tabCoord[1]);
                char piece = matcher.group(2).charAt(0);

                String obstacles = new String();
                String nouveauxElement = new String();

                // Si on insère par le haut vers le bas
                if ((coordY == 0
                        && coordX > 0
                        && coordX < largeurPlateau - 1)
                        || (coordX == 0
                        && coordY == 0
                        && (piece == 's' || piece == 'S'))
                        || (coordX == largeurPlateau - 1
                        && coordY == 0
                        && (piece == 's' || piece == 'S'))) {
                    for (int i = coordY; i < largeurPlateau; i++) {
                        obstacles += tabCaracteres[i][coordX];
                    }
                    nouveauxElement = calculDeplacementChaine(piece, obstacles);
                    for (int i = coordY; i < nouveauxElement.length(); i++) {
                        tabCaracteres[i][coordX] = nouveauxElement.charAt(i);
                    }


                }// Si on insère par le bas vers le haut
                else if ((coordY == largeurPlateau - 1
                        && coordX > 0
                        && coordX < largeurPlateau - 1)
                        || (coordX == 0
                        && coordY == largeurPlateau - 1
                        && (piece == 'n' || piece == 'N'))
                        || (coordX == largeurPlateau - 1
                        && coordY == largeurPlateau - 1
                        && (piece == 'n' || piece == 'N'))) {
                    for (int i = coordY; i >= 0; i--) {
                        obstacles += tabCaracteres[i][coordX];
                    }
                    nouveauxElement = calculDeplacementChaine(piece, obstacles);
                    for (int i = coordY; i >= 0; i--) {
                        tabCaracteres[i][coordX] = nouveauxElement.charAt(nouveauxElement.length() - 1 - i);
                    }

                }// Si on insère par la gauche vers la droite
                else if ((coordX == 0
                        && coordY > 0
                        && coordY < largeurPlateau - 1)
                        || (coordX == 0
                        && coordY == 0
                        && piece == 'e' || piece == 'E')
                        || (coordX == 0
                        && coordY == largeurPlateau - 1
                        && piece == 'e' || piece == 'E')) {
                    for (int i = coordX; i < largeurPlateau; i++) {
                        obstacles += tabCaracteres[coordY][i];
                    }
                    nouveauxElement = calculDeplacementChaine(piece, obstacles);
                    for (int i = coordX; i < nouveauxElement.length(); i++) {
                        tabCaracteres[coordY][i] = nouveauxElement.charAt(i);
                    }

                }// Si on insère par la droite vers la gauche
                else {
                    for (int i = coordX; i >= 0; i--) {
                        obstacles += tabCaracteres[coordY][i];
                    }
                    nouveauxElement = calculDeplacementChaine(piece, obstacles);
                    for (int i = coordX; i >= 0; i--) {
                        tabCaracteres[coordY][i] = nouveauxElement.charAt(nouveauxElement.length() - 1 - i);
                    }

                }
            } else {
                throw new Exception("Le coup d'insertion spécifié n'est pas valide");
            }
        } else {
            throw new Exception("Le coup d'insertion spécifié n'est pas valide");
        }
    }

    public void deplacerPiece(String coup) throws Exception {
        if (coupDeplacementValide(coup)) {
            Pattern pattern = Pattern.compile("^D\\("
                    + "([0-" + (largeurPlateau - 1) + "]),"
                    + "([0-" + (largeurPlateau - 1) + "])"
                    + "\\)\\("
                    + "(-?[0-" + (largeurPlateau - 1) + "]),"
                    + "(-?[0-" + (largeurPlateau - 1) + "])"
                    + "\\):([nseoNSEO])");
            Matcher matcher = pattern.matcher(coup);
            if (matcher.find()) {
                int coord1Y = Integer.valueOf(matcher.group(1));
                int coord1X = Integer.valueOf(matcher.group(2));
                int coord2Y = Integer.valueOf(matcher.group(3));
                int coord2X = Integer.valueOf(matcher.group(4));
                char piece = matcher.group(5).charAt(0);

                String obstacles = new String();
                String nouveauxElement = new String();

                // si rotation
                if (coord2X == coord1X
                        && coord2Y == coord1Y) {
                    tabCaracteres[coord1Y][coord1X] = piece;
                }// si déplacement vers la droite
                else if (coord2Y == coord1Y
                        && coord2X == coord1X + 1) {
                    if (coord2X >= largeurPlateau) {
                        tabCaracteres[coord1Y][coord1X] = 'X';
                    } else if (tabCaracteres[coord2Y][coord2X] == 'X') {
                        tabCaracteres[coord1Y][coord1X] = 'X';
                        tabCaracteres[coord2Y][coord2X] = piece;
                    } else {
                        for (int i = coord2X; i < largeurPlateau; i++) {
                            obstacles += tabCaracteres[coord1Y][i];
                        }
                        nouveauxElement = calculDeplacementChaine(piece, obstacles);
                        tabCaracteres[coord1Y][coord1X] = 'X';
                        for (int i = 0; i < nouveauxElement.length(); i++) {
                            tabCaracteres[coord1Y][coord2X + i] = nouveauxElement.charAt(i);
                        }

                    }
                }// si déplacement vers la gauche
                else if (coord2Y == coord1Y
                        && coord2X == coord1X - 1) {
                    if (coord2X < 0) {
                        tabCaracteres[coord1Y][coord1X] = 'X';
                    } else if (tabCaracteres[coord2Y][coord2X] == 'X') {
                        tabCaracteres[coord1Y][coord1X] = 'X';
                        tabCaracteres[coord2Y][coord2X] = piece;
                    } else {
                        for (int i = coord2X; i >= 0; i--) {
                            obstacles += tabCaracteres[coord1Y][i];
                        }
                        nouveauxElement = calculDeplacementChaine(piece, obstacles);
                        tabCaracteres[coord1Y][coord1X] = 'X';
                        for (int i = 0; i < nouveauxElement.length(); i++) {
                            tabCaracteres[coord1Y][coord2X - i] = nouveauxElement.charAt(i);
                        }

                    }
                }// si déplacement vers le haut
                else if (coord2X == coord1X
                        && coord2Y == coord1Y - 1) {
                    if (coord2Y < 0) {
                        tabCaracteres[coord1Y][coord1X] = 'X';
                    } else if (tabCaracteres[coord2Y][coord2X] == 'X') {
                        tabCaracteres[coord1Y][coord1X] = 'X';
                        tabCaracteres[coord2Y][coord2X] = piece;
                    } else {
                        for (int i = coord2Y; i >= 0; i--) {
                            obstacles += tabCaracteres[i][coord1X];
                        }
                        nouveauxElement = calculDeplacementChaine(piece, obstacles);
                        tabCaracteres[coord1Y][coord1X] = 'X';
                        for (int i = 0; i < nouveauxElement.length(); i++) {
                            tabCaracteres[coord2Y - i][coord1X] = nouveauxElement.charAt(i);
                        }

                    }
                }// si déplacement vers le bas
                else {
                    if (coord2Y >= largeurPlateau) {
                        tabCaracteres[coord1Y][coord1X] = 'X';
                    } else if (tabCaracteres[coord2Y][coord2X] == 'X') {
                        tabCaracteres[coord1Y][coord1X] = 'X';
                        tabCaracteres[coord2Y][coord2X] = piece;
                    } else {
                        for (int i = coord2Y; i < largeurPlateau; i++) {
                            obstacles += tabCaracteres[i][coord1X];
                        }
                        nouveauxElement = calculDeplacementChaine(piece, obstacles);
                        tabCaracteres[coord1Y][coord1X] = 'X';
                        for (int i = 0; i < nouveauxElement.length(); i++) {
                            tabCaracteres[coord2Y + i][coord1X] = nouveauxElement.charAt(i);
                        }

                    }
                }

            } else {
                throw new Exception("Le coup de déplacement spécifié n'est pas valide");
            }
        } else {
            throw new Exception("Le coup de déplacement spécifié n'est pas valide");
        }

    }

    public HashSet<String> getCoupsPossibles(int numJoueur) {
        char piece;
        if (numJoueur == 1) {
            piece = 'N';
        } else {
            piece = 'n';
        }

        HashSet<String> coupsPossibles = new HashSet<String>();
        String coup = new String();

        if (Character.isUpperCase(piece)) {

            if (getNbSurPlateau(piece) < nbPiecesReserve) {
                // calcul de tous les coups insertions par le haut
                for (int i = 0; i < largeurPlateau; i++) {
//                    coup = "I(0," + i + "):N";
//                    if (coupInsertionValide(coup)) {
//                        coupsPossibles.add(coup);
//                    }
                    coup = "I(0," + i + "):S";
                    if (coupInsertionValide(coup)) {
                        coupsPossibles.add(coup);
                    }
                    coup = "I(0," + i + "):E";
                    if (coupInsertionValide(coup)) {
                        coupsPossibles.add(coup);
                    }
                    coup = "I(0," + i + "):O";
                    if (coupInsertionValide(coup)) {
                        coupsPossibles.add(coup);
                    }
                }
                // calcul de tous les coups insertions par le bas
                for (int i = 0; i < largeurPlateau; i++) {
                    coup = "I(" + (largeurPlateau - 1) + "," + i + "):N";
                    if (coupInsertionValide(coup)) {
                        coupsPossibles.add(coup);
                    }
//                    coup = "I(" + (largeurPlateau - 1) + "," + i + "):S";
//                    if (coupInsertionValide(coup)) {
//                        coupsPossibles.add(coup);
//                    }
                    coup = "I(" + (largeurPlateau - 1) + "," + i + "):E";
                    if (coupInsertionValide(coup)) {
                        coupsPossibles.add(coup);
                    }
                    coup = "I(" + (largeurPlateau - 1) + "," + i + "):O";
                    if (coupInsertionValide(coup)) {
                        coupsPossibles.add(coup);
                    }
                }
                // calcul de tous les coups insertions par la gauche
                for (int i = 0; i < largeurPlateau; i++) {
                    coup = "I(" + i + ",0):N";
                    if (coupInsertionValide(coup)) {
                        coupsPossibles.add(coup);
                    }
                    coup = "I(" + i + ",0):S";
                    if (coupInsertionValide(coup)) {
                        coupsPossibles.add(coup);
                    }
                    coup = "I(" + i + ",0):E";
                    if (coupInsertionValide(coup)) {
                        coupsPossibles.add(coup);
                    }
//                    coup = "I(" + i + ",0):O";
//                    if (coupInsertionValide(coup)) {
//                        coupsPossibles.add(coup);
//                    }
                }
                // calcul de tous les coups insertions par la droite
                for (int i = 0; i < largeurPlateau; i++) {
                    coup = "I(" + i + "," + (largeurPlateau - 1) + "):N";
                    if (coupInsertionValide(coup)) {
                        coupsPossibles.add(coup);
                    }
                    coup = "I(" + i + "," + (largeurPlateau - 1) + "):S";
                    if (coupInsertionValide(coup)) {
                        coupsPossibles.add(coup);
                    }
//                    coup = "I(" + i + "," + (largeurPlateau - 1) + "):E";
//                    if (coupInsertionValide(coup)) {
//                        coupsPossibles.add(coup);
//                    }
                    coup = "I(" + i + "," + (largeurPlateau - 1) + "):O";
                    if (coupInsertionValide(coup)) {
                        coupsPossibles.add(coup);
                    }
                }
            }

            // calcul des coups de déplacements
            for (int i = 0; i < tabCaracteres.length; i++) {
                for (int j = 0; j < tabCaracteres.length; j++) {
                    if (tabCaracteres[i][j] == 'N'
                            || tabCaracteres[i][j] == 'S'
                            || tabCaracteres[i][j] == 'E'
                            || tabCaracteres[i][j] == 'O') {
                        // rotations
                        coup = "D(" + i + "," + j + ")(" + i + "," + j + "):N";
                        if (coupDeplacementValide(coup)) {
                            coupsPossibles.add(coup);
                        }
                        coup = "D(" + i + "," + j + ")(" + i + "," + j + "):S";
                        if (coupDeplacementValide(coup)) {
                            coupsPossibles.add(coup);
                        }
                        coup = "D(" + i + "," + j + ")(" + i + "," + j + "):E";
                        if (coupDeplacementValide(coup)) {
                            coupsPossibles.add(coup);
                        }
                        coup = "D(" + i + "," + j + ")(" + i + "," + j + "):O";
                        if (coupDeplacementValide(coup)) {
                            coupsPossibles.add(coup);
                        }


                        // déplacement vers le haut
                        coup = "D(" + i + "," + j + ")(" + (i - 1) + "," + j + "):N";
                     //   System.out.println("Coup vers le haut: " + coup + coupDeplacementValide(coup));
                        if (coupDeplacementValide(coup)) {
                            coupsPossibles.add(coup);
                            
                        }
                        coup = "D(" + i + "," + j + ")(" + (i - 1) + "," + j + "):S";
                        if (coupDeplacementValide(coup)) {
                            coupsPossibles.add(coup);
                        }
                        coup = "D(" + i + "," + j + ")(" + (i - 1) + "," + j + "):E";
                        if (coupDeplacementValide(coup)) {
                            coupsPossibles.add(coup);
                        }
                        coup = "D(" + i + "," + j + ")(" + (i - 1) + "," + j + "):O";
                        if (coupDeplacementValide(coup)) {
                            coupsPossibles.add(coup);
                        }


                        // déplacement vers le bas
                        coup = "D(" + i + "," + j + ")(" + (i + 1) + "," + j + "):N";
                        if (coupDeplacementValide(coup)) {
                            coupsPossibles.add(coup);
                        }
                        coup = "D(" + i + "," + j + ")(" + (i + 1) + "," + j + "):S";
                        if (coupDeplacementValide(coup)) {
                            coupsPossibles.add(coup);
                        }
                        coup = "D(" + i + "," + j + ")(" + (i + 1) + "," + j + "):E";
                        if (coupDeplacementValide(coup)) {
                            coupsPossibles.add(coup);
                        }
                        coup = "D(" + i + "," + j + ")(" + (i + 1) + "," + j + "):O";
                        if (coupDeplacementValide(coup)) {
                            coupsPossibles.add(coup);
                        }

                        // déplacement vers la droite
                        coup = "D(" + i + "," + j + ")(" + i + "," + (j + 1) + "):N";
                        if (coupDeplacementValide(coup)) {
                            coupsPossibles.add(coup);
                        }
                        coup = "D(" + i + "," + j + ")(" + i + "," + (j + 1) + "):S";
                        if (coupDeplacementValide(coup)) {
                            coupsPossibles.add(coup);
                        }
                        coup = "D(" + i + "," + j + ")(" + i + "," + (j + 1) + "):E";
                        if (coupDeplacementValide(coup)) {
                            coupsPossibles.add(coup);
                        }
                        coup = "D(" + i + "," + j + ")(" + i + "," + (j + 1) + "):O";
                        if (coupDeplacementValide(coup)) {
                            coupsPossibles.add(coup);
                        }

                        // déplacement vers la gauche
                        coup = "D(" + i + "," + j + ")(" + i + "," + (j - 1) + "):N";
                        if (coupDeplacementValide(coup)) {
                            coupsPossibles.add(coup);
                        }
                        coup = "D(" + i + "," + j + ")(" + i + "," + (j - 1) + "):S";
                        if (coupDeplacementValide(coup)) {
                            coupsPossibles.add(coup);
                        }
                        coup = "D(" + i + "," + j + ")(" + i + "," + (j - 1) + "):E";
                        if (coupDeplacementValide(coup)) {
                            coupsPossibles.add(coup);
                        }
                        coup = "D(" + i + "," + j + ")(" + i + "," + (j - 1) + "):O";
                        if (coupDeplacementValide(coup)) {
                            coupsPossibles.add(coup);
                        }
                    }

                }

            }

        } else {
            if (getNbSurPlateau(piece) < nbPiecesReserve) {
                // calcul de tous les coups insertions par le haut
                for (int i = 0; i < largeurPlateau; i++) {
//                    coup = "I(0," + i + "):n";
//                    if (coupInsertionValide(coup)) {
//                        coupsPossibles.add(coup);
//                    }
                    coup = "I(0," + i + "):s";
                    if (coupInsertionValide(coup)) {
                        coupsPossibles.add(coup);
                    }
                    coup = "I(0," + i + "):e";
                    if (coupInsertionValide(coup)) {
                        coupsPossibles.add(coup);
                    }
                    coup = "I(0," + i + "):o";
                    if (coupInsertionValide(coup)) {
                        coupsPossibles.add(coup);
                    }
                }
                // calcul de tous les coups insertions par le bas
                for (int i = 0; i < largeurPlateau; i++) {
                    coup = "I(" + (largeurPlateau - 1) + "," + i + "):n";
                    if (coupInsertionValide(coup)) {
                        coupsPossibles.add(coup);
                    }
//                    coup = "I(" + (largeurPlateau - 1) + "," + i + "):s";
//                    if (coupInsertionValide(coup)) {
//                        coupsPossibles.add(coup);
//                    }
                    coup = "I(" + (largeurPlateau - 1) + "," + i + "):e";
                    if (coupInsertionValide(coup)) {
                        coupsPossibles.add(coup);
                    }
                    coup = "I(" + (largeurPlateau - 1) + "," + i + "):o";
                    if (coupInsertionValide(coup)) {
                        coupsPossibles.add(coup);
                    }
                }
                // calcul de tous les coups insertions par la gauche
                for (int i = 0; i < largeurPlateau; i++) {
                    coup = "I(" + i + ",0):n";
                    if (coupInsertionValide(coup)) {
                        coupsPossibles.add(coup);
                    }
                    coup = "I(" + i + ",0):s";
                    if (coupInsertionValide(coup)) {
                        coupsPossibles.add(coup);
                    }
                    coup = "I(" + i + ",0):e";
                    if (coupInsertionValide(coup)) {
                        coupsPossibles.add(coup);
                    }
//                    coup = "I(" + i + ",0):o";
//                    if (coupInsertionValide(coup)) {
//                        coupsPossibles.add(coup);
//                    }
                }
                // calcul de tous les coups insertions par la droite
                for (int i = 0; i < largeurPlateau; i++) {
                    coup = "I(" + i + "," + (largeurPlateau - 1) + "):n";
                    if (coupInsertionValide(coup)) {
                        coupsPossibles.add(coup);
                    }
                    coup = "I(" + i + "," + (largeurPlateau - 1) + "):s";
                    if (coupInsertionValide(coup)) {
                        coupsPossibles.add(coup);
                    }
//                    coup = "I(" + i + "," + (largeurPlateau - 1) + "):e";
//                    if (coupInsertionValide(coup)) {
//                        coupsPossibles.add(coup);
//                    }
                    coup = "I(" + i + "," + (largeurPlateau - 1) + "):o";
                    if (coupInsertionValide(coup)) {
                        coupsPossibles.add(coup);
                    }
                }
            }

            // calcul des coups de déplacements
            for (int i = 0; i < tabCaracteres.length; i++) {
                for (int j = 0; j < tabCaracteres.length; j++) {
                    if (tabCaracteres[i][j] == 'n'
                            || tabCaracteres[i][j] == 's'
                            || tabCaracteres[i][j] == 'e'
                            || tabCaracteres[i][j] == 'o') {
                        // rotations
                        coup = "D(" + i + "," + j + ")(" + i + "," + j + "):n";
                        if (coupDeplacementValide(coup)) {
                            coupsPossibles.add(coup);
                        }
                        coup = "D(" + i + "," + j + ")(" + i + "," + j + "):s";
                        if (coupDeplacementValide(coup)) {
                            coupsPossibles.add(coup);
                        }
                        coup = "D(" + i + "," + j + ")(" + i + "," + j + "):e";
                        if (coupDeplacementValide(coup)) {
                            coupsPossibles.add(coup);
                        }
                        coup = "D(" + i + "," + j + ")(" + i + "," + j + "):o";
                        if (coupDeplacementValide(coup)) {
                            coupsPossibles.add(coup);
                        }


                        // déplacement vers le haut
                        coup = "D(" + i + "," + j + ")(" + (i - 1) + "," + j + "):n";
                        if (coupDeplacementValide(coup)) {
                            coupsPossibles.add(coup);
                        }
                        coup = "D(" + i + "," + j + ")(" + (i - 1) + "," + j + "):s";
                        if (coupDeplacementValide(coup)) {
                            coupsPossibles.add(coup);
                        }
                        coup = "D(" + i + "," + j + ")(" + (i - 1) + "," + j + "):e";
                        if (coupDeplacementValide(coup)) {
                            coupsPossibles.add(coup);
                        }
                        coup = "D(" + i + "," + j + ")(" + (i - 1) + "," + j + "):o";
                        if (coupDeplacementValide(coup)) {
                            coupsPossibles.add(coup);
                        }


                        // déplacement vers le bas
                        coup = "D(" + i + "," + j + ")(" + (i + 1) + "," + j + "):n";
                        if (coupDeplacementValide(coup)) {
                            coupsPossibles.add(coup);
                        }
                        coup = "D(" + i + "," + j + ")(" + (i + 1) + "," + j + "):s";
                        if (coupDeplacementValide(coup)) {
                            coupsPossibles.add(coup);
                        }
                        coup = "D(" + i + "," + j + ")(" + (i + 1) + "," + j + "):e";
                        if (coupDeplacementValide(coup)) {
                            coupsPossibles.add(coup);
                        }
                        coup = "D(" + i + "," + j + ")(" + (i + 1) + "," + j + "):o";
                        if (coupDeplacementValide(coup)) {
                            coupsPossibles.add(coup);
                        }

                        // déplacement vers la droite
                        coup = "D(" + i + "," + j + ")(" + i + "," + (j + 1) + "):n";
                        if (coupDeplacementValide(coup)) {
                            coupsPossibles.add(coup);
                        }
                        coup = "D(" + i + "," + j + ")(" + i + "," + (j + 1) + "):s";
                        if (coupDeplacementValide(coup)) {
                            coupsPossibles.add(coup);
                        }
                        coup = "D(" + i + "," + j + ")(" + i + "," + (j + 1) + "):e";
                        if (coupDeplacementValide(coup)) {
                            coupsPossibles.add(coup);
                        }
                        coup = "D(" + i + "," + j + ")(" + i + "," + (j + 1) + "):o";
                        if (coupDeplacementValide(coup)) {
                            coupsPossibles.add(coup);
                        }

                        // déplacement vers la gauche
                        coup = "D(" + i + "," + j + ")(" + i + "," + (j - 1) + "):n";
                        if (coupDeplacementValide(coup)) {
                            coupsPossibles.add(coup);
                        }
                        coup = "D(" + i + "," + j + ")(" + i + "," + (j - 1) + "):s";
                        if (coupDeplacementValide(coup)) {
                            coupsPossibles.add(coup);
                        }
                        coup = "D(" + i + "," + j + ")(" + i + "," + (j - 1) + "):e";
                        if (coupDeplacementValide(coup)) {
                            coupsPossibles.add(coup);
                        }
                        coup = "D(" + i + "," + j + ")(" + i + "," + (j - 1) + "):o";
                        if (coupDeplacementValide(coup)) {
                            coupsPossibles.add(coup);
                        }
                    }

                }

            }
        }
        return coupsPossibles;
    }

    @Override
    public Object clone() throws CloneNotSupportedException {
        try {
            PlateauCaracteres plateauCaracteres = new PlateauCaracteres();
            plateauCaracteres.setTabCaracteres(this.getTabCaracteres());
            return plateauCaracteres;
        } catch (Exception e) {
            System.out.println(e.getMessage() + "\n Impossible CLONAGE");
            return null;
        }

    }
}
